#include "ssl_ctx_holder.h"

#include <openssl/err.h>
#include <vector>
#include <memory>
#include <mutex>

SSL_CTX* SSLCtxHolder::SSL_CTX_ = nullptr;

static int SSL_LOCK_CNT = 0;
static std::vector<std::unique_ptr<std::mutex>> SSL_LOCK_VEC;
 
static unsigned long getThreadId() {
#ifdef _WIN32
    return static_cast<unsigned long>(GetCurrentThreadId());
#else
    return static_cast<unsigned long>(pthread_self());
#endif // _WIN32
}

static void lockThread4SSL(int mode, int n, const char* file, int line) {
    if (mode & CRYPTO_LOCK) {
        SSL_LOCK_VEC[n]->lock();
    }
    else {
        SSL_LOCK_VEC[n]->unlock();
    }
}

bool SSLCtxHolder::init(const char* cert, const char* key) {
    // 初始化
    SSL_library_init();
    SSL_load_error_strings();

    //// 保证多线程安全
    SSL_LOCK_CNT = CRYPTO_num_locks();
    for (int i = 0; i < SSL_LOCK_CNT; ++i) {
        SSL_LOCK_VEC.emplace_back(std::make_unique<std::mutex>());
    }
    CRYPTO_set_id_callback(getThreadId);
    CRYPTO_set_locking_callback(lockThread4SSL);

    // 创建SSL_CTX变量
    // 1.1.0+版本的SSL_CTX对象是线程安全的，可以不设置一堆回调函数。但SSL对象不是线程安全，如果要跨线程调用需要加锁
    const SSL_METHOD* m = TLS_server_method();
    SSL_CTX_ = SSL_CTX_new(m);
    if (!SSL_CTX_ ||
        SSL_CTX_use_certificate_file(SSL_CTX_, cert, SSL_FILETYPE_PEM) <= 0 ||
        SSL_CTX_use_PrivateKey_file(SSL_CTX_, key, SSL_FILETYPE_PEM) <= 0 ||
        SSL_CTX_check_private_key(SSL_CTX_) <= 0) 
    {
        ERR_print_errors_fp(stderr);
        SSL_CTX_free(SSL_CTX_);
        SSL_CTX_ = nullptr;
        return false;
    }


    SSL_CTX_set_verify(SSL_CTX_, SSL_VERIFY_NONE, nullptr);
    SSL_CTX_set_session_cache_mode(SSL_CTX_, SSL_SESS_CACHE_SERVER);
    // 设置至少为 TLS 1.2
    SSL_CTX_set_min_proto_version(SSL_CTX_, TLS1_2_VERSION);
    return true;
}

void SSLCtxHolder::destroy() { 
    if (SSL_CTX_) {
        SSL_CTX_free(SSL_CTX_);
        SSL_CTX_ = nullptr;
    }
}

SSL_CTX* SSLCtxHolder::get() { 
    return SSL_CTX_; 
}